package com.kylin.hibernate;

import java.io.Serializable;
import java.util.List;

import org.apache.log4j.Logger;
import org.hibernate.Criteria;
import org.hibernate.LockMode;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.Example;
import org.hibernate.criterion.LogicalExpression;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;

import com.kylin.common.exception.BusinessException;
import com.kylin.common.exception.SystemException;

/**
 * 支持事务的dao
 * 此类中每个方法都是未提交的，可以多个方法在一个事务中执行
 * 要想使方法执行生效，必须显式调用 commitTansction
 * @author ly
 *
 */
public class TransactionDAO {
	protected static Logger log = Logger.getLogger(TransactionDAO.class);
	private Transaction tx ;

	public TransactionDAO(){
		
	}
	public Session getSession() {
		return HibernateSessionFactory.getSession();
	}

	public void startTansction(){
		getSession().beginTransaction();
	}

	public void commitTansction(){
		getSession().getTransaction().commit();
	}

	public void rollbackTansction(){
		getSession().getTransaction().rollback();
	}

	public void save(Object transientInstance) throws BusinessException {
		
		try {
			getSession().save(transientInstance);
		} catch (RuntimeException re) {
			if (re.getCause() instanceof java.sql.BatchUpdateException)
				throw new BusinessException(re.getCause().getMessage(), re.getCause());
			else
				throw new SystemException(re.getMessage(), re);
		}
	}

	public Object saveRtObj(Object transientInstance) throws BusinessException {
		
		try {
			Serializable id = getSession().save(transientInstance);
			return findById( transientInstance.getClass(),new Long(id.toString()));
		} catch (RuntimeException re) {
			if (re.getCause() instanceof java.sql.BatchUpdateException)
				throw new BusinessException(re.getCause().getMessage(), re.getCause());
			else
				throw new SystemException(re.getMessage(), re);
		}
	}

	public Serializable saveRtId(Object transientInstance) throws BusinessException {
		
		try {
			Serializable id = getSession().save(transientInstance);
			return id;
		} catch (RuntimeException re) {
			if (re.getCause() instanceof java.sql.BatchUpdateException)
				throw new BusinessException(re.getCause().getMessage(), re.getCause());
			else
				throw new SystemException(re.getMessage(), re);
		}
	}

	public void saveOrUpdate(Object transientInstance) throws BusinessException {
		
		try {
			getSession().saveOrUpdate(transientInstance);
		} catch (RuntimeException re) {
			if (re.getCause() instanceof java.sql.BatchUpdateException)
				throw new BusinessException(re.getCause().getMessage(), re.getCause());
			else
				throw new SystemException(re.getMessage(), re);
		}
	}

	public void update(Object transientInstance) throws BusinessException {
		
		try {
			getSession().update(transientInstance);
		} catch (RuntimeException re) {
			if (re.getCause() instanceof java.sql.BatchUpdateException)
				throw new BusinessException(re.getCause().getMessage(), re.getCause());
			else
				throw new SystemException(re.getMessage(), re);
		}
	}

	public void delete(Object persistentInstance) throws BusinessException {
		
		try {
			getSession().delete(persistentInstance);
		} catch (RuntimeException re) {
			if (re.getCause() instanceof java.sql.BatchUpdateException)
				throw new BusinessException(re.getCause().getMessage(), re.getCause());
			else
				throw new SystemException(re.getMessage(), re);
		}
	}

	public void deleteById(Class clz,java.lang.Long id) throws BusinessException {
		
		try {
			getSession().delete( findById( clz,id) );
		} catch (RuntimeException re) {
			if (re.getCause() instanceof java.sql.BatchUpdateException)
				throw new BusinessException(re.getCause().getMessage(), re.getCause());
			else
				throw new SystemException(re.getMessage(), re);
		}
	}

	public Object findById(Class clz, java.lang.Long id) throws BusinessException {
		try {
			Object instance = getSession().get(clz, id);
			return instance;
		} catch (RuntimeException re) {
			if (re.getCause() instanceof java.sql.BatchUpdateException)
				throw new BusinessException(re.getCause().getMessage(), re.getCause());
			else
				throw new SystemException(re.getMessage(), re);
		}
	}

	public List findAllByLanguage(Class clz, String locale, Order orderby)
			throws BusinessException {
		log.info(" findAllByLanguage(" + clz + "," + locale + ")");
		Criteria criteria = getSession().createCriteria(clz);
		criteria = criteria.add(Restrictions.eq("language", locale));
		try {
			if(orderby != null)
				return criteria.addOrder(orderby).list();
			else
				return criteria.list();
		} catch (Exception re) {
			if (re.getCause() instanceof java.sql.BatchUpdateException)
				throw new BusinessException(re.getCause().getMessage(), re.getCause());
			else
				throw new SystemException(re.getMessage(), re);
		}
	}

	public List findAll(Class clz, Order orderby) throws BusinessException {
		Criteria criteria = getSession().createCriteria(clz);
		try {
			if(orderby != null)
				return criteria.addOrder(orderby).list();
			else
				return criteria.list();
		} catch (RuntimeException re) {
			if (re.getCause() instanceof java.sql.BatchUpdateException)
				throw new BusinessException(re.getCause().getMessage(), re.getCause());
			else
				throw re;
		}
	}

	public List findByExample(Object instance) throws BusinessException {
		return findByExample(instance, null);
	}

	/**
	 * 简单查询方法，查询条件为传入的对象的各属性值，即用此对象不为空的属性做为查询条件 例： XXObj.setName("xx");
	 * XXObj.setTime("2007-11-1"); findByExample(XXObj) 的条件是 name='xx' and
	 * time='2007-11-1'
	 * 
	 * @param instance
	 *            查询的实体对象
	 * @param orderby
	 *            排序对象
	 * @return
	 * @throws BusinessException
	 */
	public List findByExample(Object instance, Order orderby) throws BusinessException {
		log.info(" findByExample(" + instance + ")");
		Criteria criteria = getSession().createCriteria(instance.getClass());
		criteria = criteria.add(Example.create(instance));
		if (orderby != null) {
			criteria = criteria.addOrder(orderby);
		}
		try {
			return criteria.list();
		} catch (RuntimeException re) {
			if (re.getCause() instanceof java.sql.BatchUpdateException)
				throw new BusinessException(re.getCause().getMessage(), re.getCause());
			else
				throw re;
		}
	}

	public List findByProperty(Class clz, String propertyName, Object value, Order orderby)
			throws BusinessException {
		PropertyCondition[] pcs = new PropertyCondition[] { new PropertyCondition(propertyName,
				value, "=") };
		return findByPropertyConditions(clz, pcs, orderby);
	}

	public List findByProperty(Class clz, String propertyName, Object value)
			throws BusinessException {
		PropertyCondition[] pcs = new PropertyCondition[] { new PropertyCondition(propertyName,
				value, "=") };
		return findByPropertyConditions(clz, pcs, null);
	}

	/**
	 * 组合条件查询，支持多条件的与查询
	 * 
	 * @param instance
	 * @param pConditions
	 * @param orderby
	 * @return
	 * @throws BusinessException
	 */
	public List findByPropertyConditions(Class clz, PropertyCondition[] pConditions,
			Order orderby) throws BusinessException {
		log.info(" findByExample : " + clz + "pcondition.length=" + pConditions.length);
		Criteria criteria = getSession().createCriteria(clz);
		if (pConditions != null) {
			System.out.println("PropertyCondition length=" + pConditions.length);
			for (int i = 0; i < pConditions.length; i++) {
				Criterion  se = getCriterion(pConditions[i].getPropertyName(),
						pConditions[i].getPropertyValue(), pConditions[i].getRelationalOperator());
				criteria = criteria.add(se);
			}
		} else {
			// System.out.println("PropertyCondition is NULL----" );
		}
		if (orderby != null) {
			criteria = criteria.addOrder(orderby);
		}
		// System.out.println(" criteria.getAlias="+criteria.getAlias());
		try {
			return criteria.list();
		} catch (RuntimeException re) {
			if (re.getCause() instanceof java.sql.BatchUpdateException)
				throw new BusinessException(re.getCause().getMessage(), re.getCause());
			else
				throw re;
		}
	}

	public Criteria createCriteria(LogicalExpression expr,Class clz){
		Criteria criteria = getSession().createCriteria(clz);;
		return criteria.add(expr);
	}
	
	/**
	 * 由info存储的信息构建一个查询器 一般在内存或其它地方持久存放 CriteriaInfo对象，就可随时转换成可用的查询器
	 * 
	 * @param instance
	 * @param pConditions
	 * @param orderby
	 * @return
	 */
	public Criteria getCriteriaFromInfo(CriteriaInfo info) {
		log.debug(" get Criteria : " + info);
		Criteria criteria = getSession().createCriteria(info.getClz());
		PropertyCondition[] pConditions = info.getPConditions();
		if (pConditions != null) {
			// System.out.println("PropertyCondition
			// length="+pConditions.length);
			for (int i = 0; i < pConditions.length; i++) {
				Criterion  se = getCriterion(pConditions[i].getPropertyName(),
						pConditions[i].getPropertyValue(), pConditions[i].getRelationalOperator());
				criteria = criteria.add(se);
			}
		} else {
			// System.out.println("PropertyCondition is NULL----" );
		}
		if (info.getOrderby() != null) {
			criteria = criteria.addOrder(info.getOrderby());
		}

		return criteria;
	}

	/**
	 * 
	 * like(String propertyName, Object value)：属性值与目标值满足模式匹配 lt(String
	 * propertyName, Object value)：属性值小于目标值 le(String propertyName, Object
	 * value)：属性值小于等于目标值 gt(String propertyName, Object value)：属性值大于目标值
	 * ge(String propertyName, Object value)：属性值大于等于目标值
	 * 
	 * @param propertyName
	 * @param value
	 * @param orderby
	 * @param op
	 * @return
	 */
	public Criterion getCriterion(String propertyName, Object value, String op) {
		if (PropertyCondition.OPERATOR_EQ.equals(op)){
			if(value == null)
				return Restrictions.isNull(propertyName);
			else
				return Restrictions.eq(propertyName, value);
		}else if (PropertyCondition.OPERATOR_GE.equals(op))
			return Restrictions.ge(propertyName, value);
		else if (PropertyCondition.OPERATOR_GT.equals(op))
			return Restrictions.gt(propertyName, value);
		else if (PropertyCondition.OPERATOR_LE.equals(op))
			return Restrictions.le(propertyName, value);
		else if (PropertyCondition.OPERATOR_LT.equals(op))
			return Restrictions.lt(propertyName, value);
		else if (PropertyCondition.OPERATOR_LIKE.equals(op))
			return Restrictions.like(propertyName, value);
		else if (PropertyCondition.OPERATOR_ISNULL.equals(op))
			return Restrictions.isNull(propertyName);
		else
			return null;
	}

	public Object merge(Object detachedInstance) throws BusinessException {
		try {
			Object result = getSession().merge(detachedInstance);
			return result;
		} catch (RuntimeException re) {
			if (re.getCause() instanceof java.sql.BatchUpdateException)
				throw new BusinessException(re.getCause().getMessage(), re.getCause());
			else
				throw re;
		}
	}

	public void attachDirty(Object instance) throws BusinessException {
		try {
			getSession().saveOrUpdate(instance);
		} catch (RuntimeException re) {
			if (re.getCause() instanceof java.sql.BatchUpdateException)
				throw new BusinessException(re.getCause().getMessage(), re.getCause());
			else
				throw re;
		}
	}

	public void attachClean(Object instance) throws BusinessException {
		try {
			getSession().lock(instance, LockMode.NONE);
		} catch (RuntimeException re) {
			if (re.getCause() instanceof java.sql.BatchUpdateException)
				throw new BusinessException(re.getCause().getMessage(), re.getCause());
			else
				throw re;
		}
	}


}
